package cn.huixh.blindbox.service.impl;

import cn.huixh.blindbox.annotation.UpdateCache;
import cn.huixh.blindbox.common.Common;
import cn.huixh.blindbox.common.ReturnCode;
import cn.huixh.blindbox.exception.impl.BizException;
import cn.huixh.blindbox.mapper.FileMapper;
import cn.huixh.blindbox.mapper.NoteMapper;
import cn.huixh.blindbox.pojo.dto.NoteDTO;
import cn.huixh.blindbox.pojo.po.File;
import cn.huixh.blindbox.pojo.po.Note;
import cn.huixh.blindbox.pojo.vo.NoteVO;
import cn.huixh.blindbox.service.BoxService;
import cn.huixh.blindbox.service.TokenService;
import cn.huixh.blindbox.utils.RedisUtil;
import cn.huixh.blindbox.utils.ToolsUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author huixh
 * @version 1.0
 * @date 2022/5/13 11:34
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class BoxServiceImpl extends ServiceImpl< NoteMapper, Note > implements BoxService {

    final TokenService tokenService;

    final RedisUtil redisUtil;

    final FileMapper fileMapper;

    final ToolsUtil toolsUtil;

    /**
     * 系统启动将所有用户导入 redis 中
     */
    @PostConstruct
    public void initNote() {
        redisUtil.del(Common.MAN, Common.WOMAN);
        List< Note > noteList = new LambdaQueryChainWrapper<>(baseMapper)
                .and(e -> e.eq(Note::getSex, Common.WOMAN).or().eq(Note::getSex, Common.MAN)).list();
        for (Note note : noteList) {
            if (note.getSex().equals(Common.MAN)) {
                redisUtil.sAdd(Common.MAN, note);
            } else {
                redisUtil.sAdd(Common.WOMAN, note);
            }
        }
        log.info("用户缓存完成！");
    }

    /**
     * 随机获取
     *
     * @return NoteVO
     */
    @Override
    public NoteVO getRandomNote(String sex) {
        Assert.isTrue(Common.MAN.equals(sex) || Common.WOMAN.equals(sex));
        long size = redisUtil.sSize(sex);
        Assert.isTrue(size > 0L, () -> new BizException(ReturnCode.RC500));
        Note obj = (Note) redisUtil.sRandomMember(sex);
        return NoteVO.of(obj);
    }

    /**
     * 放置纸条
     *
     * @param token   用户token
     * @param noteDTO 纸条
     */
    @Override
    @UpdateCache
    public void putNote(String token, NoteDTO noteDTO) {
        String sex = noteDTO.getSex();
        Assert.isTrue(Common.MAN.equals(sex) || Common.WOMAN.equals(sex));
        String id = tokenService.getAccountId(token);
        String accountEmail = tokenService.getAccountEmail(token);
        Note note = Note.builder()
                .accountId(id)
                .sex(sex)
                .createAuthor(Common.AUTHOR_USER + accountEmail)
                .wechat(noteDTO.getWeChatNumber())
                .content(noteDTO.getMessage())
                .build();
        save(note);
        String noteId = note.getId();
        List< String > fileList = noteDTO.getFiles();
        new LambdaUpdateChainWrapper<>(fileMapper)
                .set(File::getNoteId, noteId)
                .in(File::getId, fileList)
                .update();
        redisUtil.sAdd(noteDTO.getSex(), note);
    }

    /**
     * 获取自己的发布
     *
     * @param id
     * @return
     */
    @Override
    public List< NoteVO > getSelf(String id) {

        List< Note > list = new LambdaQueryChainWrapper<>(baseMapper).eq(Note::getAccountId, id).list();
        List< NoteVO > noteVOS = new ArrayList<>(list.size());
        for (Note note : list) {
            noteVOS.add(NoteVO.of(note));
        }
        return noteVOS;
    }
}
